package com.onpositive.gamemaker.spriteeditor;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.ScrollBar;

public class ImageScrollingControl extends Composite
{
	protected static final Color FRAME_COLOR = Display.getDefault().getSystemColor(SWT.COLOR_RED);
	Image originalImage;
	private Rectangle frameBounds;

	public ImageScrollingControl(final Composite parent, int style)
	{
		super(parent, style);
		setLayout(new FillLayout());
		final Canvas canvas = new Canvas(this, SWT.HORIZONTAL | SWT.VERTICAL);
		// final Image image = originalImage;
		final Point origin = new Point(0, 0);
		final ScrollBar hBar = canvas.getHorizontalBar();
		hBar.addListener(SWT.Selection, new Listener()
		{
			public void handleEvent(Event e)
			{
				int hSelection = hBar.getSelection();
				int destX = -hSelection - origin.x;
				Rectangle rect = originalImage.getBounds();
				canvas.scroll(destX, 0, 0, 0, rect.width, rect.height, false);
				origin.x = -hSelection;
			}
		});
		final ScrollBar vBar = canvas.getVerticalBar();
		vBar.addListener(SWT.Selection, new Listener()
		{
			public void handleEvent(Event e)
			{
				int vSelection = vBar.getSelection();
				int destY = -vSelection - origin.y;
				if (originalImage != null)
				{
					Rectangle rect = originalImage.getBounds();
					canvas.scroll(0, destY, 0, 0, rect.width, rect.height, false);
					origin.y = -vSelection;
				}
			}
		});
		canvas.addListener(SWT.Resize, new Listener()
		{
			public void handleEvent(Event e)
			{
				updateSize(canvas, origin, hBar, vBar);
			}

		});
		canvas.addListener(SWT.Paint, new Listener()
		{
			public void handleEvent(Event e)
			{
				if (originalImage == null)
					return;
				GC gc = e.gc;
				gc.drawImage(originalImage, origin.x, origin.y);
				Rectangle rect = originalImage.getBounds();
				Rectangle client = canvas.getClientArea();
				int marginWidth = client.width - rect.width;
				if (marginWidth > 0)
				{
					gc.fillRectangle(rect.width, 0, marginWidth, client.height);
				}
				int marginHeight = client.height - rect.height;
				if (marginHeight > 0)
				{
					gc.fillRectangle(0, rect.height, client.width, marginHeight);
				}
				if (frameBounds != null)
				{
					gc.setForeground(FRAME_COLOR);
					gc.drawRectangle(frameBounds);
				}
			}
		});
	}

	/**
	 * @return the originalImage
	 */
	public Image getImage()
	{
		return originalImage;
	}

	/**
	 * @param originalImage
	 *            the originalImage to set
	 */
	public void setImage(Image originalImage)
	{
		this.originalImage = originalImage;
		redraw();
	}

	protected void updateSize(final Canvas canvas, final Point origin, final ScrollBar hBar, final ScrollBar vBar)
	{
		if (originalImage == null)
			return;
		Rectangle rect = originalImage.getBounds();
		Rectangle client = canvas.getClientArea();
		hBar.setMaximum(rect.width);
		vBar.setMaximum(rect.height);
		hBar.setThumb(Math.min(rect.width, client.width));
		vBar.setThumb(Math.min(rect.height, client.height));
		int hPage = rect.width - client.width;
		int vPage = rect.height - client.height;
		int hSelection = hBar.getSelection();
		int vSelection = vBar.getSelection();
		if (hSelection >= hPage)
		{
			if (hPage <= 0)
				hSelection = 0;
			origin.x = -hSelection;
		}
		if (vSelection >= vPage)
		{
			if (vPage <= 0)
				vSelection = 0;
			origin.y = -vSelection;
		}
		canvas.redraw();
	}

	@Override
	public void setBounds(int x, int y, int width, int height)
	{
		// TODO Auto-generated method stub
		super.setBounds(x, y, width, height);
	}

	public void setFrameBounds(Rectangle frameBounds)
	{
		this.frameBounds = frameBounds;
		redraw();
	}

}
